﻿using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MongoDB.Driver;
using MongoDB.Bson;
using MongoDB.Driver.Builders;
using MongoDB.Driver.Linq;

namespace ProductCatalog.WebApi.Tests
{
    [TestClass]
    public class MongoTest
    {
        MongoCollection<BsonDocument> products;

        [TestInitialize]
        public void Init()
        {
            var client = new MongoClient(ProductCatalog.WebApi.DataLayer.CloudConfiguration.GetMongolabConnectionString());
            var server = client.GetServer();
            var database = server.GetDatabase(ProductCatalog.WebApi.DataLayer.CloudConfiguration.GetProductDatabaseName());
            products = database.GetCollection<BsonDocument>(ProductCatalog.WebApi.DataLayer.CloudConfiguration.GetProductCollectionName());
        }

        [TestMethod]
        public void MongoCountTest()
        {
            var countQuery = @"
{
    $match:{
        _id: ObjectId('5178f823bbb2732280d139cd')
    }
},
{
    $project:{
        reviews:1
    }
},
{
    $unwind:'$reviews'
},
{
    $group:{
        _id: 'result',
        reviewCount: { $sum: 1 }
    }
}";
            var docs = ProductCatalog.WebApi.DataLayer.MongoHelper.ParseToBsonDocumentArray(countQuery);
            var result = products.Aggregate(docs);
            var resultDoc = result.ResultDocuments
                .Single();
            var count = resultDoc["reviewCount"].ToInt32();

            Assert.AreEqual(count, 3);
        }

        [TestMethod]
        public void MongoAvgTest()
        {
            var countQuery = @"
{
    $match:{
        _id: ObjectId('5178f823bbb2732280d139cd')
    }
},
{
    $project:{
        reviews:1
    }
},
{
    $unwind:'$reviews'
},
{
    $group:{
        _id: 'result',
        reviewAvg: { $avg: '$reviews.rating' }
    }
}";
            var docs = ProductCatalog.WebApi.DataLayer.MongoHelper.ParseToBsonDocumentArray(countQuery);
            var result = products.Aggregate(docs);
            var resultDoc = result.ResultDocuments
                .Single();

            var avg = Math.Round(resultDoc["reviewAvg"].ToDouble(), 2);

            Assert.AreEqual(avg, 4.67D);
        }

        [TestMethod]
        public void MongoMultiIdsTest()
        {
            var countQuery = @"
{
    $match:{
        _id: { $in: [ObjectId('5178f823bbb2732280d139cd'), ObjectId('517aaa380fdb8c0b2cfda211')] }
    }
},
{
    $group:{
        _id: 'result',
        productCount: { $sum: 1 }
    }
}";
            var docs = ProductCatalog.WebApi.DataLayer.MongoHelper.ParseToBsonDocumentArray(countQuery);
            var result = products.Aggregate(docs);
            var resultDoc = result.ResultDocuments
                .Single();

            var count = resultDoc["productCount"].ToInt32();

            Assert.AreEqual(count, 2);
        }

        [TestMethod]
        public void MongoPagingTest()
        {

            var pagingQuery = @"
{
    $match:{
        _id: ObjectId('XXXIDXXX')
    }
},
{
    $project:{
        _id: 0,
        reviews: 1
    }
},
{
    $unwind:'$reviews'
},
{
    $skip: XXXSKIPXXX
},
{
    $limit: XXXLIMITXXX
}";
            // hate me for this .. but this way the json stays clean and without double {{, which would be neccessary for string format
            pagingQuery = pagingQuery.Replace("XXXIDXXX", "5178f823bbb2732280d139cd");
            pagingQuery = pagingQuery.Replace("XXXSKIPXXX", 1.ToString());
            pagingQuery = pagingQuery.Replace("XXXLIMITXXX", 2.ToString());
            var docs = ProductCatalog.WebApi.DataLayer.MongoHelper.ParseToBsonDocumentArray(pagingQuery);
            var documents = products.Aggregate(docs).ResultDocuments
                .Select(i => i["reviews"].AsBsonDocument)
                .ToArray();

            Assert.AreEqual(documents.Length, 2);
            Assert.AreEqual(documents[0]["reviewId"], "5170bed10fdb8c0e7c671d33");
            Assert.AreEqual(documents[1]["reviewId"], "5171bed10fdb8c0e7c671d34");
        }
    }
}
